/**
 * NEURON IIoT System for Industry 4.0
 * Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 **/

/*
 * DO NOT EDIT THIS FILE MANUALLY!
 * It was automatically generated by `json-autotype`.
 */

#include <stdlib.h>
#include <string.h>

#include <jansson.h>

#include "msg.h"
#include "utils/log.h"
#include "json/json.h"

#include "neu_json_datalayers.h"

#include <openssl/md5.h>

void generate_fixed_uuid(const char *input, char *out)
{
    unsigned char hash[MD5_DIGEST_LENGTH];
    MD5_CTX       md5_ctx;

    MD5_Init(&md5_ctx);
    MD5_Update(&md5_ctx, input, strlen(input));
    MD5_Final(hash, &md5_ctx);

    snprintf(
        out, 37,
        "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
        hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
        hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14],
        hash[15]);
}

int neu_json_encode_datalayers_get_groups_resp(void *object, void *param)
{
    int                            ret = 0;
    neu_json_get_subscribe_resp_t *resp =
        (neu_json_get_subscribe_resp_t *) param;

    json_t *node_array = json_array();

    for (int i = 0; i < resp->n_group; i++) {
        neu_json_get_subscribe_resp_group_t *g = &resp->groups[i];
        if (!g->driver || !g->group)
            continue;

        char node_id[37];
        generate_fixed_uuid(g->driver, node_id);

        json_t *node_obj       = NULL;
        json_t *children_array = NULL;

        for (size_t j = 0; j < json_array_size(node_array); j++) {
            node_obj = json_array_get(node_array, j);
            if (strcmp(json_string_value(json_object_get(node_obj, "id")),
                       node_id) == 0) {
                break;
            }
            node_obj = NULL;
        }

        if (!node_obj) {
            node_obj = json_object();
            json_object_set_new(node_obj, "id", json_string(node_id));
            json_object_set_new(node_obj, "name", json_string(g->driver));
            json_object_set_new(node_obj, "category", json_integer(1));
            children_array = json_array();
            json_object_set_new(node_obj, "children", children_array);
            json_array_append_new(node_array, node_obj);
        } else {
            children_array = json_object_get(node_obj, "children");
        }

        char group_id[37];
        char group_uuid_input[256];
        snprintf(group_uuid_input, sizeof(group_uuid_input), "%s-%s", g->driver,
                 g->group);
        generate_fixed_uuid(group_uuid_input, group_id);

        json_t *group_obj = json_object();
        json_object_set_new(group_obj, "id", json_string(group_id));
        json_object_set_new(group_obj, "name", json_string(g->group));
        json_object_set_new(group_obj, "category", json_integer(2));
        json_object_set_new(group_obj, "children", json_array());

        json_array_append_new(children_array, group_obj);
    }

    json_t *final_obj = json_object();
    json_object_set_new(final_obj, "error", json_integer(0));
    json_object_set_new(final_obj, "children", node_array);

    neu_json_elem_t elems[] = { {
        .name         = NULL,
        .t            = NEU_JSON_OBJECT,
        .v.val_object = final_obj,
    } };

    ret = neu_json_encode_field(object, elems, NEU_JSON_ELEM_SIZE(elems));

    json_decref(final_obj);

    return ret;
}

int neu_json_encode_datalayers_get_tags_resp(void *json_object_param,
                                             void *param)
{
    neu_resp_get_sub_driver_tags_t *resp =
        (neu_resp_get_sub_driver_tags_t *) param;
    json_t *group_array = json_array();

    for (unsigned int i = 0; i < utarray_len(resp->infos); i++) {
        neu_resp_get_sub_driver_tags_info_t *info =
            (neu_resp_get_sub_driver_tags_info_t *) utarray_eltptr(resp->infos,
                                                                   i);

        char group_uuid_input[256], group_id[37];
        snprintf(group_uuid_input, sizeof(group_uuid_input), "%s-%s",
                 info->driver, info->group);
        generate_fixed_uuid(group_uuid_input, group_id);

        json_t *group_obj = json_object();
        json_object_set_new(group_obj, "id", json_string(group_id));
        json_object_set_new(group_obj, "name", json_string(info->group));
        json_object_set_new(group_obj, "category", json_integer(2));

        json_t *tag_array = json_array();

        if (info->tags) {
            for (unsigned int j = 0; j < utarray_len(info->tags); j++) {
                neu_datatag_t *tag =
                    (neu_datatag_t *) utarray_eltptr(info->tags, j);

                char tag_uuid_input[512], tag_id[37];
                snprintf(tag_uuid_input, sizeof(tag_uuid_input), "%s-%s-%s",
                         info->driver, info->group, tag->name);
                generate_fixed_uuid(tag_uuid_input, tag_id);

                json_t *tag_obj = json_object();
                json_object_set_new(tag_obj, "id", json_string(tag_id));
                json_object_set_new(tag_obj, "name", json_string(tag->name));
                json_object_set_new(tag_obj, "type", json_integer(tag->type));
                json_object_set_new(tag_obj, "category", json_integer(3));
                json_object_set_new(tag_obj, "leaf", json_true());
                json_object_set_new(tag_obj, "children", json_array());

                json_array_append_new(tag_array, tag_obj);
            }
        }

        json_object_set_new(group_obj, "children", tag_array);
        json_array_append_new(group_array, group_obj);
    }

    json_t *final_obj = json_object();
    json_object_set_new(final_obj, "error", json_integer(0));
    json_object_set_new(final_obj, "children", group_array);

    neu_json_elem_t elems[] = { {
        .name         = NULL,
        .t            = NEU_JSON_OBJECT,
        .v.val_object = final_obj,
    } };

    int ret = neu_json_encode_field(json_object_param, elems,
                                    NEU_JSON_ELEM_SIZE(elems));
    json_decref(final_obj);
    return ret;
}

int neu_json_encode_datalayers_get_tag_resp(void *json_object_param,
                                            void *param)
{
    neu_resp_get_sub_driver_tags_t *resp =
        (neu_resp_get_sub_driver_tags_t *) param;
    json_t *node_array = json_array();

    for (unsigned int i = 0; i < utarray_len(resp->infos); i++) {
        neu_resp_get_sub_driver_tags_info_t *info =
            (neu_resp_get_sub_driver_tags_info_t *) utarray_eltptr(resp->infos,
                                                                   i);

        char node_id[37];
        char node_uuid_input[128];
        snprintf(node_uuid_input, sizeof(node_uuid_input), "%s", info->driver);
        generate_fixed_uuid(node_uuid_input, node_id);

        json_t *node_obj = NULL;
        for (size_t j = 0; j < json_array_size(node_array); j++) {
            node_obj = json_array_get(node_array, j);
            if (strcmp(json_string_value(json_object_get(node_obj, "id")),
                       node_id) == 0) {
                break;
            }
            node_obj = NULL;
        }

        if (!node_obj) {
            node_obj = json_object();
            json_object_set_new(node_obj, "id", json_string(node_id));
            json_object_set_new(node_obj, "name", json_string(info->driver));
            json_object_set_new(node_obj, "category", json_integer(1));
            json_t *node_children = json_array();
            json_object_set_new(node_obj, "children", node_children);
            json_array_append_new(node_array, node_obj);
        }

        json_t *group_obj = NULL;
        char    group_id[37];
        char    group_uuid_input[256];
        snprintf(group_uuid_input, sizeof(group_uuid_input), "%s-%s",
                 info->driver, info->group);
        generate_fixed_uuid(group_uuid_input, group_id);

        json_t *children_array = json_object_get(node_obj, "children");

        for (size_t k = 0; k < json_array_size(children_array); k++) {
            group_obj = json_array_get(children_array, k);
            if (strcmp(json_string_value(json_object_get(group_obj, "id")),
                       group_id) == 0) {
                break;
            }
            group_obj = NULL;
        }

        if (!group_obj) {
            group_obj = json_object();
            json_object_set_new(group_obj, "id", json_string(group_id));
            json_object_set_new(group_obj, "name", json_string(info->group));
            json_object_set_new(group_obj, "category", json_integer(2));
            json_t *group_children = json_array();
            json_object_set_new(group_obj, "children", group_children);
            json_array_append_new(children_array, group_obj);
        }

        json_t *tag_array = json_object_get(group_obj, "children");

        if (info->tags) {
            for (unsigned int j = 0; j < utarray_len(info->tags); j++) {
                neu_datatag_t *tag =
                    (neu_datatag_t *) utarray_eltptr(info->tags, j);

                char tag_id[37];
                char tag_uuid_input[512];
                snprintf(tag_uuid_input, sizeof(tag_uuid_input), "%s-%s-%s",
                         info->driver, info->group, tag->name);
                generate_fixed_uuid(tag_uuid_input, tag_id);

                json_t *tag_obj = json_object();
                json_object_set_new(tag_obj, "id", json_string(tag_id));
                json_object_set_new(tag_obj, "name", json_string(tag->name));
                json_object_set_new(tag_obj, "type", json_integer(tag->type));
                json_object_set_new(tag_obj, "category", json_integer(3));
                json_object_set_new(tag_obj, "leaf", json_true());
                json_object_set_new(tag_obj, "children", json_array());

                json_array_append_new(tag_array, tag_obj);
            }
        }
    }

    json_t *final_obj = json_object();
    json_object_set_new(final_obj, "error", json_integer(0));
    json_object_set_new(final_obj, "children", node_array);

    neu_json_elem_t elems[] = { {
        .name         = NULL,
        .t            = NEU_JSON_OBJECT,
        .v.val_object = final_obj,
    } };

    int ret = neu_json_encode_field(json_object_param, elems,
                                    NEU_JSON_ELEM_SIZE(elems));
    json_decref(final_obj);
    return ret;
}